package com.dc.commons.service;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import javax.persistence.MappedSuperclass;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Transactional;

import com.dc.commons.jdbc.SimpleRowMapper;
import com.dc.commons.procedure.DcCallableStatementCallback;
import com.dc.commons.procedure.DcCallableStatementCreator;
import com.dc.commons.procedure.DcProcedureTemplate;
import com.dc.commons.utils.Reflections;
import com.google.common.collect.Lists;

/*******************************************************************************<P>
 * 文件名: BaseService.java <br>
 * 版本: 1.0<br>
 * 描述:<br>
 * 版权所有: <br>
 * <P>
 * 创建者: 王建栋 <br>
 * 创建日期: 2016年3月16日 下午8:31:36<br>
 * 修改者: <br>
 * 修改日期: <br>
 * 修改说明: <br>
 ******************************************************************************/
@MappedSuperclass
@Transactional(readOnly=false)
public abstract class BaseService<T> {

	@Autowired(required=false)
	private DcProcedureTemplate dcProcedureTemplate;
	
	/**
	 * 获取 存储过程模板， 如果 所有的存储过程全部来自一个系统 则可以在base中直接配置<br>
	 * 否则 可以通过重载 返回自己的模板。
	 * @return
	 */
	public DcProcedureTemplate getDcProcedureTemplate() {
		return dcProcedureTemplate;
	}
	/**
	 * 实体类类型(由构造方法自动赋值)
	 */
	private Class<T> entityClass;
	
	/**
	 * 构造方法，根据实例类自动获取实体类类型
	 */
	public BaseService() {
		entityClass = Reflections.getClassGenricType(getClass());
	}
	
	
	/**
	 * 分页查询,使用默认的mapper
	 * @param pageable
	 * @param list
	 * @param proc
	 * @return List<T>
	 */
	public Page<T> queryPager(final Pageable pageable,final List<?>list,String proc){
		return queryPager(pageable, list, proc, new SimpleRowMapper<T>(entityClass));
	}
	
	/**
	 * 查询 存储过程返回列表对象 使用默认的结果集处理
	 * @param list
	 * @param proc
	 * @return List<T>
	 */
	public List<T> query(final List<?>list,String proc){
		return query(list, proc,new SimpleRowMapper<T>(entityClass));
	}
	/**
	 * 查询 存储过程返回列表对象
	 * @param list
	 * @param proc
	 * @param rowMapper
	 * @return List<T>
	 */
	public List<T> query(final List<?>list,String proc,final RowMapper<T> rowMapper){
		return getDcProcedureTemplate().query(new DcCallableStatementCreator() {
			
			@Override
			public CallableStatement createCallableStatement(Connection connection, CallableStatement callableStatement)
					throws SQLException {
				int count=2;
				for(Object obj:list){
					if(obj instanceof Date){
						Date date=(Date)obj;
						callableStatement.setTimestamp(count++, new Timestamp(date.getTime()));
					}else{
						callableStatement.setObject(count++, obj);
					}
				}
				return callableStatement;
			}
		}, new DcCallableStatementCallback<List<T>>(){

			@Override
			public List<T> doInCallableStatement(CallableStatement callableStatement, ResultSet rs, long totalCount)
					throws SQLException {
				List<T> list=Lists.newArrayList();
				while(rs.next()){
					T t=rowMapper.mapRow(rs, 0);
					list.add(t);
				}
				return list;
			}
			
		}, proc);
	}
	/**
	 *  分页查询
	 * @param pageable
	 * @param list
	 * @param proc
	 * @param rowMapper
	 * @return page<T>
	 */
	public Page<T> queryPager(final Pageable pageable,final List<?>list,String proc,final RowMapper<T> rowMapper){
		return getDcProcedureTemplate().queryPager(new DcCallableStatementCreator(){

			@Override
			public CallableStatement createCallableStatement(Connection connection, CallableStatement callableStatement)
					throws SQLException {
				int count=3;
				for(Object obj:list){
					if(obj instanceof Date){
						Date date=(Date)obj;
						callableStatement.setTimestamp(count++, new Timestamp(date.getTime()));
					}else{
						callableStatement.setObject(count++, obj);
					}
				}
				return callableStatement;
			}
			
		}, new DcCallableStatementCallback<Page<T>>(){

			@Override
			public Page<T> doInCallableStatement(CallableStatement callableStatement, ResultSet rs, long totalCount)
					throws SQLException {
				List<T> list=Lists.newArrayList();
				while(rs.next()){
					T t=rowMapper.mapRow(rs, 0);
					list.add(t);
				}
				return new PageImpl<T>(list, pageable, totalCount);
			}
			
		}, proc);
	}
}
